// (c) 2008 Kickstone Technology Ltd

#include "stdafx.h"
#include <shobjidl.h>
#include <atlwin.h>
#include "RebarHandler.h"
#include "IEWindow.h"
#include "DlgAbout.h"
#include "ButtonDemoBHO.h"


// This must match the name given in the registry file
const wchar_t* const pszButtonTxt = L"Demo Button";


CRebarHandler::CRebarHandler(HWND hWndToolbar, CIEWindow *ieWindow) {
	m_hWnd=hWndToolbar;
	m_hWndRebar=NULL;
	m_hWndToolbar=NULL;
	m_hWndTooltip=NULL;
	m_buttonID=0;
	m_ieVer=ieWindow->getIEVersion();
	m_ieWindow=ieWindow;
	getRebarHWND();
	m_hMenu = LoadMenu(_AtlBaseModule.m_hInst, MAKEINTRESOURCE(IDR_BHOMENU)); 
}

CRebarHandler::~CRebarHandler() {
	if (m_hMenu)
		DestroyMenu(m_hMenu);
}

///////////////////////////////////////////////////////////////////////////
// subclass functions
///////////////////////////////////////////////////////////////////////////

void CRebarHandler::subclass(){
	SubclassWindow(m_hWndRebar);
}

void CRebarHandler::unsubclass(){
	UnsubclassWindow();
}

///////////////////////////////////////////////////////////////////////////
// Message Handlers
///////////////////////////////////////////////////////////////////////////

// Show the menu
LRESULT CRebarHandler::onNotifyDropDown(WPARAM wParam, LPNMHDR pNMHDR, BOOL& bHandled){
	bHandled=false;
	LPNMTOOLBAR pNMTOOLBAR=(LPNMTOOLBAR)pNMHDR;
	// How to determine which window called this? Might need to pregress up the window chain to find it!
	if (pNMTOOLBAR->hdr.hwndFrom == m_hWndToolbar && pNMTOOLBAR->iItem==m_buttonID){
		RECT rc;
		POINT pt;

		// get main window rectangle
		::GetWindowRect(m_hWnd, &rc);
		// get position of the button
		switch (m_ieVer){
			case 6 : pt.x=pNMTOOLBAR->rcButton.left; break;
			case 7 : pt.x=pNMTOOLBAR->rcButton.right; break;
		}
		pt.y=pNMTOOLBAR->rcButton.bottom;
		::ClientToScreen(m_hWndToolbar, &pt);		// get screen coordinates of button
		if (m_ieVer==7 && pt.x>rc.right)
			pt.x=rc.right;

		// If the mouse click took place inside the client 
		// area, execute the application-defined function 
		// that displays the shortcut menu. 
		if (!m_hMenu) 
			return true;
		HMENU hMenuTrackPopup = GetSubMenu(m_hMenu, 0); 
		CButtonDemoBHO *bho=m_ieWindow->getCurrentBHO();

		DWORD style= TPM_LEFTBUTTON | TPM_RETURNCMD;
		if (m_ieVer==7 || pt.x>rc.right)
			style|=TPM_RIGHTALIGN;
		DWORD d=TrackPopupMenu(hMenuTrackPopup, style, pt.x, pt.y, 0, m_hWnd, NULL); 
		if (d){
			switch (d){ 
				case ID_MENU_BUTTON : bho->menuPressed(); break;	// call the toolbar button code
				case ID_MENU_ABOUT : CDlgAbout::openDialog(m_hWnd); break;
			}
		}
		bHandled=true;
	}
	return S_OK;
}

// Toolbar has changed so find the button
LRESULT CRebarHandler::onNotifyToolbarChange(WPARAM wParam, LPNMHDR pNMHDR, BOOL& bHandled){
	bHandled=false;
	if (m_ieVer==6){
		if (m_hWndToolbar)
			findButton(m_hWndToolbar);
		else
			scanForToolbarSlow();
	}
	if (m_buttonID)
		setButtonMenu();

	return S_OK;
}

// Toolbar has been redrawn so find it in IE7
LRESULT CRebarHandler::onNotifyCustomDraw(WPARAM wParam, LPNMHDR pNMHDR, BOOL& bHandled){
	bHandled=false;
	if (m_ieVer==7){
		if (m_buttonID==0){
			scanTooltips();
			if (m_buttonID>0)
				setButtonMenu();
		} 
	}
	return S_OK;
}

// Toolbar being redrawn so find the toolbar and add the dropdown
LRESULT CRebarHandler::onSetRedraw(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){
	bHandled=false;
	if (m_ieVer==6){
		if (!m_hWndToolbar)
			scanForToolbarSlow();
		if (m_hWndToolbar){
			findButton(m_hWndToolbar);
			if (m_buttonID>0)
				setButtonMenu();
		}
	}
	return S_OK;
}

// toolbar finished being adjusted so add the dropdown
LRESULT CRebarHandler::onNotifyEndAdjust(WPARAM wParam, LPNMHDR pNMHDR, BOOL& bHandled){
	bHandled=false;
	if (m_ieVer==7){
		if (m_buttonID>0)
			setButtonMenu();
	}
	return S_OK;
}

// IE7 - scan the tooltips for the buttons in the toolbar looking for ours
void CRebarHandler::scanTooltips(){
	if (m_buttonID==0){
		int cnt;
		wchar_t buf[100];
		TOOLINFO ti;
		ti.cbSize=sizeof(ti);
		ti.lpszText=buf;
		ti.hwnd=m_hWndToolbar;

		TBBUTTON button;
		cnt=SendMessage(m_hWndToolbar, TB_BUTTONCOUNT,0,0);
		for (int i=0;i<cnt;i++){
			SendMessage(m_hWndToolbar, TB_GETBUTTON, i, (LPARAM)&button);
			ti.uId=button.idCommand;
			SendMessage(m_hWndTooltip, TTM_GETTEXT, 100, (LPARAM)&ti);
			if (wcscmp(buf, pszButtonTxt)==0)
				m_buttonID=button.idCommand;
		}
	}
}

// inject the drop down arrow
void CRebarHandler::setButtonMenu(){
	TBBUTTONINFO inf;
	inf.cbSize=sizeof(inf);
	inf.dwMask=TBIF_STYLE;
	inf.fsStyle=BTNS_DROPDOWN | BTNS_AUTOSIZE ;
	SendMessage(m_hWndToolbar, TB_SETBUTTONINFO, m_buttonID, (LPARAM)&inf);
}

// for IE6, scan the toolbars looking for our button
// Need to do this as we can't be sure what order the toolbars are in
void CRebarHandler::scanForToolbarSlow(){
	HWND tmp=NULL;
	while (true){
		tmp=::FindWindowEx(m_hWndRebar, tmp, _T("ToolbarWindow32"), L"");
		if (tmp==NULL)
			break;
		if (findButton(tmp)){
			m_hWndToolbar=tmp;
			break;
		}
	}
}

// given a toolbar handle, scan for the button
bool CRebarHandler::findButton(HWND hWndToolbar){
	wchar_t buf[100];
	int len;
	TBBUTTON button;
	int cnt=SendMessage(hWndToolbar, TB_BUTTONCOUNT,0,0);
	for (int i=0;i<cnt;i++){
		SendMessage(hWndToolbar, TB_GETBUTTON, i, (LPARAM)&button);
		if (button.iString==-1)
			continue;
		if (IS_INTRESOURCE(button.iString)){
			len=::SendMessage(hWndToolbar, TB_GETSTRING, MAKEWPARAM(100,button.iString), (LPARAM)&buf);
			if (len<=0)
				buf[0]=0;
		} else {
			_snwprintf_s(buf,  99, L"%s",(wchar_t *)button.iString);
			buf[99]=0;
		}
		if (wcscmp(buf,pszButtonTxt)==0){
			// found it, so save the ID
			m_buttonID=button.idCommand;
			return true;
		}
	}
	m_buttonID=0;
	return false;
}

// find the rebar hWnd
void CRebarHandler::getRebarHWND(){
	HWND tmp=::FindWindowEx(m_hWnd, NULL, _T("CommandBarClass"),  NULL);
	if (tmp){
		m_hWndRebar=::FindWindowEx(tmp, NULL, _T("ReBarWindow32"), NULL);
		if (!m_hWndRebar)
			return;
		m_hWndToolbar=::FindWindowEx(m_hWndRebar, NULL, _T("ToolbarWindow32"), NULL);
		if (!m_hWndToolbar)
			return;
		m_hWndTooltip=(HWND)SendMessage(m_hWndToolbar, TB_GETTOOLTIPS, 0, 0);
		m_ieVer=7;
	} else {
		if (!getRebarHWNDIE6Quick()){
			tmp=::FindWindowEx(m_hWnd, NULL, _T("WorkerW"),  NULL);
			if (!tmp)
				return;
			m_hWndRebar=::FindWindowEx(tmp, NULL, _T("ReBarWindow32"), NULL);
		}
		findToolbarIE6();
		m_ieVer=6;
	}
}

// quick find the toolbar hWnd IE6
void CRebarHandler::findToolbarIE6(){
   m_hWndToolbar = ::GetDlgItem(m_hWndRebar, 0x0000A000);
}

// quick find the rebar hWnd IE6
bool CRebarHandler::getRebarHWNDIE6Quick(){
	HWND hWndCmdbar = ::GetDlgItem(m_hWnd, 0x0000A005);

	if (hWndCmdbar) {
		m_hWndRebar = FindWindowEx(hWndCmdbar, NULL, L"ReBarWindow32", NULL);
		if (m_hWndRebar) 
			return true;
	}
	return false;
}